#include <iostream>

#include "io.h"

IO::~IO()
{

}

IO::IO(): QObject()
{
    engine1 = nullptr;
    engine2 = nullptr;
    printf("aaaa\n");
}

void IO::loadEngine1()
{
    printf("enter path of engine1:\n");
    std::string path;
    std::getline(std::cin, path);
    path1 = QString(path.c_str());

    //engine1 = new QProcess();
    //connect(engine1, SIGNAL(readyReadStandardOutput()), this, SLOT(getEngineData1()));
}

void IO::loadEngine2()
{
    printf("enter path of engine2:\n");
    std::string path;
    std::getline(std::cin, path);
    path2 = QString(path.c_str());

    //engine2 = new QProcess();
    //connect(engine2, SIGNAL(readyReadStandardOutput()), this, SLOT(getEngineData2()));
}

void IO::getSimulateAmount()
{
    printf("enter simulate amount:\n");
    scanf("%d", &simTime);
}

void IO::setLayout1(int layout)
{
    chess[2][0] = (layout % 10) * 10 + 1;
    layout /= 10;
    chess[1][1] = (layout % 10) * 10 + 1;
    layout /= 10;
    chess[1][0] = (layout % 10) * 10 + 1;
    layout /= 10;
    chess[0][2] = (layout % 10) * 10 + 1;
    layout /= 10;
    chess[0][1] = (layout % 10) * 10 + 1;
    layout /= 10;
    chess[0][0] = (layout % 10) * 10 + 1;
}

void IO::setLayout2(int layout)
{
    chess[2][4] = (layout % 10) * 10 + 2;
    layout /= 10;
    chess[3][3] = (layout % 10) * 10 + 2;
    layout /= 10;
    chess[3][4] = (layout % 10) * 10 + 2;
    layout /= 10;
    chess[4][2] = (layout % 10) * 10 + 2;
    layout /= 10;
    chess[4][3] = (layout % 10) * 10 + 2;
    layout /= 10;
    chess[4][4] = (layout % 10) * 10 + 2;
}

void IO::getMode()
{
    printf("enter mode(1 for even):\n");
    scanf("%d", &mode);
}

void IO::sendToEngine1(const QString & cmd)
{
    engine1->write(cmd.toLatin1().constData(), cmd.length());
    engine1->waitForBytesWritten();
}

void IO::sendToEngine2(const QString & cmd)
{
    engine2->write(cmd.toLatin1().constData(), cmd.length());
    engine2->waitForBytesWritten();
}

void IO::getEngineData1()
{
    static char buf[10];
    QString data = engine1->readAll();
    if (flag1 == 0)
    {
        // name?
        name1 = data;
        //printf("%s\n", name1.toStdString().c_str());
        flag1 = 1;
    }
    else if (flag1 == 1)
    {
        // your layout
        sscanf(data.toStdString().c_str(), "%d", &layout1);
        //printf("engine1:%d\n", layout1);
        if(who1 == 1)
            setLayout1(layout1);
        else if(who1 == 2)
            setLayout2(layout1);
        flag1 = 2;
    }
    else if (flag1 == 2)
    {
        // move

        int from, to, dice;
        char buffer[50] = {0};
        sscanf(data.toStdString().c_str(), "%s%d%d%d", buf, &from, &to, &dice);
        sprintf(buffer, "move %02d %02d %d\r\n\0", from, to, dice);
        //lastMove = QString("move %1 %2 %3\r\n").arg(from).arg(to).arg(dice);
        lastMove = QString(buffer);
        printf("engine1:");
        printf(lastMove.toStdString().c_str());
        printf("\n");
        makeMove(from, to);
    }
}

void IO::getEngineData2()
{
    static char buf[10];
    QString data = engine2->readAll();
    if (flag2 == 0)
    {
        // name?
        name2 = data;
        //printf("%s\n", name2.toStdString().c_str());
        flag2 = 1;
    }
    else if (flag2 == 1)
    {
        // your layout
        sscanf(data.toStdString().c_str(), "%d", &layout2);
        //printf("engine2:%d\n", layout2);
        if(who2 == 1)
            setLayout1(layout2);
        else if(who2 == 2)
            setLayout2(layout2);
        flag2 = 2;
    }
    else if (flag2 == 2)
    {
        // move

        int from, to, dice;
        char buffer[50] = {0};
        sscanf(data.toStdString().c_str(), "%s%d%d%d", buf, &from, &to, &dice);
        //lastMove = QString("move %1 %2 %3\r\n").arg(from).arg(to).arg(dice);
        sprintf(buffer, "move %02d %02d %d\r\n\0", from, to, dice);
        lastMove = QString(buffer);
        printf("engine2:");
        printf(lastMove.toStdString().c_str());
        printf("\n");
        makeMove(from, to);
    }
}

int IO::simulateOnce(int first)
{
    //

    if(engine1)
    {
        sendToEngine1("stop\r\n");
        engine1->close();
        //printf("bbb\n");
        delete engine1;
    }
    engine1 = nullptr;
    if(engine2)
    {
        sendToEngine2("stop\r\n");
        engine2->close();
        delete engine2;
    }
    engine2 = nullptr;
    printf("simulate:\n");

    flag1 = 0;
    flag2 = 0;
    who1 = 1;
    who2 = 2;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            chess[i][j] = 0;
        }
    }

    engine1 = new QProcess(this);
    engine2 = new QProcess(this);
    connect(engine1, SIGNAL(readyReadStandardOutput()), this, SLOT(getEngineData1()));
    connect(engine2, SIGNAL(readyReadStandardOutput()), this, SLOT(getEngineData2()));

    //printf("%s\n", path1.toStdString().c_str());
    //printf("%s\n", path2.toStdString().c_str());

    engine1->start(path1);
    engine1->waitForStarted();
    engine2->start(path2);
    engine2->waitForStarted();


    sendToEngine1("name?\r\n");
    engine1->waitForReadyRead();
    if(first == 1)
        sendToEngine1("redfirst\r\n");
    else if(first == 2)
        sendToEngine1("bluefirst\r\n");
    //engine1->waitForBytesWritten();
    sendToEngine1("red\r\n");
    engine1->waitForReadyRead();
    sendToEngine1("begin\r\n");
    //engine1->waitForBytesWritten();

    sendToEngine2("name?\r\n");
    engine2->waitForReadyRead();
    if(first == 1)
        sendToEngine2("redfirst\r\n");
    else if(first == 2)
        sendToEngine2("bluefirst\r\n");
    //engine2->waitForBytesWritten();
    sendToEngine2("blue\r\n");
    engine2->waitForReadyRead();
    sendToEngine2("begin\r\n");
    //engine2->waitForBytesWritten();

    sendToEngine1(QString("%1\r\n").arg(layout2));
    //engine1->waitForBytesWritten();
    sendToEngine2(QString("%1\r\n").arg(layout1));

    //printf("bbb\n");

    if (first == 1)
    {
        sendToEngine1(QString("%1\r\n").arg(rand() % 6 + 1));
        engine1->waitForReadyRead();
    }
    else if (first == 2)
    {
        sendToEngine2(QString("%1\r\n").arg(rand() % 6 + 1));
        engine2->waitForReadyRead();
    }
    printBoard();

    int move = 3 - first;
    int win;
    srand(time(0));
    while (!(win = gameOver()))
    {
        if (move == 1)
        {
            sendToEngine1(lastMove);
            sendToEngine1(QString("%1\r\n").arg(rand() % 6 + 1));
            engine1->waitForReadyRead();
        }
        else if (move == 2)
        {
            sendToEngine2(lastMove);
            sendToEngine2(QString("%1\r\n").arg(rand() % 6 + 1));
            engine2->waitForReadyRead();
        }
        move = 3 - move;
        printBoard();
    }

    return win;
}

void IO::makeMove(int from, int to)
{
    int x1 = from / 10;
    int y1 = from % 10;
    int x2 = to / 10;
    int y2 = to % 10;

    chess[x2][y2] = chess[x1][y1];
    chess[x1][y1] = 0;
}

int IO::getRandom()
{
    //srand(time(0));
    return rand() % 6 + 1;
}

int IO::gameOver()
{
    if (chess[0][0] % 10 == 2)
        return 2;
    if (chess[4][4] % 10 == 1)
        return 1;

    bool f1 = false;
    bool f2 = false;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            if (chess[i][j] % 10 == 1)
                f1 = true;
            if (chess[i][j] % 10 == 2)
                f2 = true;
        }
    }

    if (f1 == false)
        return 2;
    if (f2 == false)
        return 1;
    return 0;
}

void IO::simulate()
{
    int win1 = 0;
    int win2 = 0;
    for(int i = 1; i <= simTime; i++)
    {
        int win = simulateOnce(1);
        if(win == 1)
            win1++;
        else if(win == 2)
            win2++;
        printf("SIM #%d:\nwin1:%d  win2:%d\n", i, win1, win2);
    }
}

void IO::printBoard()
{
    printf("BOARD:\n");
    for(int i = 0; i < 5; i++)
    {
        for(int j = 0; j < 5; j++)
        {
            printf("%2d ", chess[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');
}
